package com.coffee.framework.web.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.coffee.common.Constants;
import com.coffee.common.MenuConstants;
import com.coffee.common.bo.LoginUser;
import com.coffee.common.bo.SysRoleBO;
import com.coffee.common.bo.SysUserBO;
import com.coffee.common.dto.LoginDTO;
import com.coffee.common.enums.*;
import com.coffee.common.exception.CustomException;
import com.coffee.common.util.AddressUtil;
import com.coffee.common.util.IpUtil;
import com.coffee.common.util.SecurityUtil;
import com.coffee.framework.web.service.IUserService;
import com.coffee.system.common.vo.*;
import com.coffee.system.entity.SysMenu;
import com.coffee.system.entity.SysRole;
import com.coffee.system.entity.SysUser;
import com.coffee.system.service.ISysMenuService;
import com.coffee.system.service.ISysRoleService;
import com.coffee.system.service.ISysUserService;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户实现类
 *
 * @author Kevin
 */
@Slf4j
@Service
public class UserServiceImpl implements IUserService {

    @Resource
    private ISysMenuService sysMenuService;

    @Resource
    private ISysUserService sysUserService;

    @Resource
    private ISysRoleService sysRoleService;

    @Override
    public String login(LoginDTO req) {
        if (StrUtil.isBlank(req.getGrantType())) {
            throw new CustomException("授权类型不能为空");
        }
        if (!GrantTypeEnum.contains(req.getGrantType())) {
            throw new CustomException("授权类型暂不支持");
        }
        SysUser sysUser = null;
        if (req.getGrantType().equals(GrantTypeEnum.USERNAME_PASSWORD.getCode())) {
            if (StrUtil.isBlank(req.getUsername())) {
                throw new CustomException("用户名不能为空");
            }
            if (StrUtil.isBlank(req.getPassword())) {
                throw new CustomException("密码不能为空");
            }
            sysUser = sysUserService.getOne(Wrappers.lambdaQuery(SysUser.class).eq(SysUser::getAccount, req.getUsername()));
            if (Objects.isNull(sysUser)) {
                log.info("登录用户：{}不存在", req.getUsername());
                throw new CustomException("登录用户不存在");
            }
            if (!SecurityUtil.matchesPassword(req.getPassword(), sysUser.getPassword())) {
                throw new CustomException("账号或密码不正确");
            }
            if (sysUser.getDelFlag().equals(DelFlagEnum.YES.getCode())) {
                log.info("登录用户：{}已被删除", req.getUsername());
                throw new CustomException("对不起，您的账号已被删除");
            }
            if (sysUser.getStatus().equals(StatusEnum.NO.getCode())) {
                log.info("登录用户：{}已被停用", req.getUsername());
                throw new CustomException("对不起，您的账号已被停用");
            }
        }
        if (req.getGrantType().equals(GrantTypeEnum.MOBILE_CODE.getCode())) {
            if (StrUtil.isBlank(req.getMobile())) {
                throw new CustomException("手机号不能为空");
            }
            if (StrUtil.isBlank(req.getCode())) {
                throw new CustomException("验证码不能为空");
            }
            // TODO，短信验证码校验，自行实现
            if (!Objects.equals(req.getCode(), Constants.DEFAULT_SMS_CODE)) {
                throw new CustomException("账号或密码不正确");
            }
            sysUser = sysUserService.getOne(Wrappers.lambdaQuery(SysUser.class).eq(SysUser::getPhone, req.getMobile()));
            if (Objects.isNull(sysUser)) {
                log.info("登录用户：{}不存在", req.getUsername());
                throw new CustomException("登录用户不存在");
            }
            if (sysUser.getDelFlag().equals(DelFlagEnum.YES.getCode())) {
                log.info("登录用户：{}已被删除", req.getUsername());
                throw new CustomException("对不起，您的账号已被删除");
            }
            if (sysUser.getStatus().equals(StatusEnum.NO.getCode())) {
                log.info("登录用户：{}已被停用", req.getUsername());
                throw new CustomException("对不起，您的账号已被停用");
            }
        }
        log.info("登录用户：{}", req.getUsername());
        SysUserBO sysUserBO = BeanUtil.copyProperties(sysUser, SysUserBO.class);
        // 查询角色列表
        List<SysRole> sysRoleList = sysRoleService.listSysRoleByUserId(sysUser.getId());
        // 设置角色列表
        sysUserBO.setRoles(sysRoleList.stream().map(item -> BeanUtil.copyProperties(item, SysRoleBO.class)).collect(Collectors.toList()));
        // 查询权限标识
        Set<String> permissions = Sets.newHashSet();
        if (SecurityUtil.isSuperAdmin(sysUser.getId())) {
            permissions.add(Constants.ALL_PERMISSION);
        } else {
            permissions = sysMenuService.getPermissionsByUserId(sysUser.getId());
        }
        // 登录
        StpUtil.login(sysUser.getId());
        LoginUser loginUser = new LoginUser();
        loginUser.setToken(StpUtil.getTokenValue());
        loginUser.setUserPlatform(UserPlatformEnum.WEB.getCode());
        loginUser.setGrantType(req.getGrantType());
        loginUser.setSysUser(sysUserBO);
        if (req.getGrantType().equals(GrantTypeEnum.USERNAME_PASSWORD.getCode())) {
            loginUser.setUsername(req.getUsername());
        }
        if (req.getGrantType().equals(GrantTypeEnum.MOBILE_CODE.getCode())) {
            loginUser.setUsername(req.getMobile());
        }
        loginUser.setLoginTime(new Date());
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        UserAgent userAgent = UserAgentUtil.parse(request.getHeader("User-Agent"));
        String ipAddress = IpUtil.getClientIp(request);
        loginUser.setIpAddress(ipAddress);
        loginUser.setLoginLocation(AddressUtil.getRealAddressByIp(ipAddress));
        loginUser.setBrowser(userAgent.getBrowser().getName());
        loginUser.setOs(userAgent.getOs().getName());
        loginUser.setPermissions(permissions);
        // 设置用户信息
        StpUtil.getTokenSession().set(Constants.LOGIN_USER_KEY, loginUser);
        return StpUtil.getTokenValue();
    }

    @Override
    public UserInfoVO getUserInfo() {
        UserInfoVO userInfoVO = new UserInfoVO();
        SysUser sysUser = sysUserService.getById(StpUtil.getLoginIdAsLong());
        // 查询角色列表
        List<SysRole> sysRoleList = sysRoleService.listSysRoleByUserId(sysUser.getId());
        List<RoleInfoVO> roleInfoVOList = sysRoleList.stream().map(item -> {
            RoleInfoVO roleInfoVO = new RoleInfoVO();
            roleInfoVO.setRoleName(item.getRoleName());
            roleInfoVO.setValue(item.getRoleCode());
            return roleInfoVO;
        }).collect(Collectors.toList());
        userInfoVO.setUserId(sysUser.getId().toString());
        userInfoVO.setUsername(sysUser.getAccount());
        userInfoVO.setRealName(sysUser.getNickname());
        userInfoVO.setAvatar(sysUser.getAvatar());
        userInfoVO.setDesc(sysUser.getRemarks());
        userInfoVO.setRoles(roleInfoVOList);
        return userInfoVO;
    }

    @Override
    public Set<String> getPermCode() {
        return SecurityUtil.getLoginUser().getPermissions();
    }

    @Override
    public List<RouteItemVO> getMenuList() {
        List<SysMenu> sysMenuList;
        SysUserBO sysUserBO = SecurityUtil.getLoginUser().getSysUser();
        if (SecurityUtil.isSuperAdmin()) {
            LambdaQueryWrapper<SysMenu> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(SysMenu::getStatus, StatusEnum.YES.getCode());
            queryWrapper.in(SysMenu::getMenuType, MenuTypeEnum.DIR.getCode(), MenuTypeEnum.MENU.getCode());
            sysMenuList = sysMenuService.list(queryWrapper);
        } else {
            sysMenuList = sysMenuService.listGrantMenuByUserId(sysUserBO.getId());
        }
        List<RouteItemVO> routeItemVOList = sysMenuList.stream()
                .filter(item -> item.getParentId().intValue() == 0)
                .sorted(Comparator.comparing(SysMenu::getSort))
                .map(item -> {
                    RouteItemVO node = convertToRoute(item);
                    node.setChildren(getChildrenList(item, sysMenuList));
                    return node;
                }).collect(Collectors.toList());
        return routeItemVOList;
    }

    @Override
    public AccountInfoVO getAccountInfo() {
        LoginUser loginUser = SecurityUtil.getLoginUser();
        SysUser sysUser = sysUserService.getById(loginUser.getSysUser().getId());
        return BeanUtil.copyProperties(sysUser, AccountInfoVO.class);
    }

    @Override
    public void saveAccountInfo(AccountInfoVO req) {
        LoginUser loginUser = SecurityUtil.getLoginUser();
        SysUser entity = BeanUtil.copyProperties(req, SysUser.class);
        entity.setId(loginUser.getSysUser().getId());
        sysUserService.updateById(entity);
    }

    private List<RouteItemVO> getChildrenList(SysMenu root, List<SysMenu> list) {
        List<RouteItemVO> childrenList = list.stream()
                .filter(item -> item.getParentId().equals(root.getId()))
                .sorted(Comparator.comparing(SysMenu::getSort))
                .map(item -> {
                    RouteItemVO node = convertToRoute(item);
                    node.setChildren(getChildrenList(item, list));
                    return node;
                }).collect(Collectors.toList());
        return childrenList;
    }

    private RouteItemVO convertToRoute(SysMenu item) {
        RouteItemVO node = new RouteItemVO();
        node.setName(StrUtil.upperFirst(item.getRoutePath()));
        node.setPath(item.getRoutePath());
        node.setComponent(item.getComponent());
        // 一级目录
        if (Objects.equals(item.getMenuType(), MenuTypeEnum.DIR.getCode()) && item.getParentId().intValue() == 0) {
            node.setPath("/" + item.getRoutePath());
            node.setComponent(MenuConstants.LAYOUT);
        }
        // 外部链接
        if (Objects.equals(item.getMenuType(), MenuTypeEnum.MENU.getCode()) && Objects.equals(item.getLinkExternal(), LinkExternalEnum.YES.getCode())) {
            node.setComponent(MenuConstants.IFRAME);
        }
        RouteMetoVO routeMetoVO = new RouteMetoVO();
        routeMetoVO.setTitle(item.getMenuName());
        routeMetoVO.setIcon(item.getIcon());
        routeMetoVO.setHideMenu(StrUtil.isNotBlank(item.getVisible()) && item.getVisible().equals(VisibleEnum.HIDE.getCode()));
        // 菜单
        if (Objects.equals(item.getMenuType(), MenuTypeEnum.MENU.getCode())) {
            routeMetoVO.setIgnoreKeepAlive(item.getKeepalive().equals(KeepaliveEnum.YES.getCode()));
        }
        // 外部链接
        if (Objects.equals(item.getMenuType(), MenuTypeEnum.MENU.getCode()) && Objects.equals(item.getLinkExternal(), LinkExternalEnum.YES.getCode())) {
            // 内嵌
            if (Objects.equals(item.getFrame(), FrameEnum.YES.getCode())) {
                routeMetoVO.setFrameSrc(item.getLinkUrl());
            }
            // 外嵌
            if (item.getFrame().equals(FrameEnum.NO.getCode())) {
                node.setPath(item.getLinkUrl());
            }
        }
        node.setMeta(routeMetoVO);
        return node;
    }

}
